/*
 * Flashlib - QB9 common Flash library
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.qb9.flashlib.net
{
	import com.qb9.flashlib.easing.Linear;
	import com.qb9.flashlib.lang.filter;
	import com.qb9.flashlib.lang.fold;
	import com.qb9.flashlib.tasks.*;
	
	import flash.events.ProgressEvent;

	/**
	 * Task that loads a group of files and completes when all files have been loaded.
	 *
	 * <p>Usage example:
	 * <pre>
	 * var group:GroupLoad = new GroupLoad()
	 * group.addLoader('file1.jpg').addEventListener(Event.COMPLETE, jpgLoaded);
	 * group.addLoader('file2.xml').addEventListener(Event.COMPLETE, xmlLoaded);
	 * group.addEventListener(GroupLoadProgressEvent.PROGRESS, updateLoadingBar);
	 * tasks.add(group);
	 * </pre>
	 * </p>
	 *
	 * @see examples/motion/MotionExample.as.
	 */
	public class GroupLoad extends Parallel
	{
		protected var _loaders:Object;

		/**
		 * Percent value at which the progress percent calculation method will change.
		 *
		 * This affects how the <code>progressPercent</code> value in <code>GroupLoadProgressEvent</code> is calculated.
		 */
		public var progressPercentCutValue:uint = 10;

		public function GroupLoad()
		{
			_loaders = {};
		}

		/**
		 * Specify a new file to be loaded.
		 *
		 * @param url URL of the filr to be loaded.
		 * @param id Unique identifier for the loader. By default it will be equal to the url.
		 */
		public function addLoader(url:String, id:String=null): LoadFile
		{
			var loader:LoadFile = new LoadFile(url, LoadFileFormat.INFER, id);
			addFile(loader);
			return loader;
		}
		
		/**
		 * Specify a new file to be loaded.
		 *
		 * @param file file to be loaded.
		 */
		public function addFile(file:LoadFile): void
		{
			if (_loaders[file.url])
				throw new Error('GroupLoad >The file "'+file.url+'" was already being loaded.');
			
			file.id = file.id || file.url;
			_loaders[file.id] = file;
			add(file);
		}

		/** @inheritDoc */
		public override function start():void
		{
			for each (var loader:LoadFile in loaders)
				loader.addEventListener(ProgressEvent.PROGRESS, onFileProgress);
			super.start();
		}

		/** @inheritDoc */
		public override function stop():void
		{
			for each (var loader:LoadFile in loaders)
				loader.removeEventListener(ProgressEvent.PROGRESS, onFileProgress);
			super.stop();
		}

		protected function onFileProgress(ev:ProgressEvent):void
		{
			dispatchEvent(new GroupLoadProgressEvent(progressPercent));
		}

		/** Get the loading progress percentage. */
		public function get progressPercent():uint
		{
			var loadsStartedPercent:uint = Linear.lerp(startedFiles, 0, 0, loaders.length, 10);
			if (loadsStartedPercent < progressPercentCutValue)
				return loadsStartedPercent;
			return Linear.lerp(bytesLoaded, 0, progressPercentCutValue, bytesTotal, 100);
		}

		/** Get the list of registered loaders. */
		public function get loaders():Array
		{
			var ret:Array = [];
			for each(var loader:LoadFile in _loaders)
				ret.push(loader);
			return ret;
		}

		protected function loadStarted(loader:LoadFile):Boolean
		{
			return loader.bytesTotal != 0;
		}

		protected function get startedFiles():uint
		{
			return filter(loaders, loadStarted).length;
		}

		protected function countBytesLoaded(loader:LoadFile, accum:uint):uint
		{
			return accum + loader.bytesLoaded;
		}
		
		/** Get the amount of bytes loaded. */
		public function get bytesLoaded():uint
		{
			return fold(loaders, countBytesLoaded, 0);
		}

		protected function countBytesTotal(loader:LoadFile,accum:uint):uint
		{
			return accum + loader.bytesTotal;
		}
		
		/** Get the total amount of bytes to be loaded. */
		public function get bytesTotal():uint
		{
			return fold(loaders, countBytesTotal, 0);
		}
	}
}
